﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace TestPrint.XMLhelp
{
    public class AppBase<T> where T : AppBase<T>
    {

        #region 字段
        private static T _instance;
        private static readonly object _objLock = new object();
        private static FileSystemWatcher m_Watcher;
        #endregion

        static AppBase()
        {
            var type = typeof(T);
            var pathAttr = (AppPathAttribute)type.GetCustomAttributes(typeof(AppPathAttribute), false).FirstOrDefault();
            if (pathAttr != null)
                FullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, pathAttr.Path);
            else
                FullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Config", type.Name + ".config");

            string fileName = Path.GetFileName(FullPath);
            string path = Path.GetDirectoryName(FullPath);
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            m_Watcher = new FileSystemWatcher();
            m_Watcher.Filter = fileName;
            m_Watcher.Path = path;
            m_Watcher.NotifyFilter = NotifyFilters.Attributes |
            NotifyFilters.CreationTime |
            NotifyFilters.DirectoryName |
            NotifyFilters.FileName |
            NotifyFilters.LastAccess |
            NotifyFilters.LastWrite |
            NotifyFilters.Security |
            NotifyFilters.Size;
            m_Watcher.Changed += new FileSystemEventHandler(OnChanged);
            m_Watcher.Created += new FileSystemEventHandler(OnChanged);
            m_Watcher.Deleted += new FileSystemEventHandler(OnChanged);
            m_Watcher.Renamed += new RenamedEventHandler(OnRenamed);
            m_Watcher.EnableRaisingEvents = true;
        }

        /// <summary>
        /// 配置文件完整路径
        /// </summary>
        public static string FullPath { get; private set; }

        private static void OnChanged(object sender, FileSystemEventArgs e)
        {
            lock (_objLock)
            {
                _instance = null;
            }
        }

        private static void OnRenamed(object sender, RenamedEventArgs e)
        {
            lock (_objLock)
            {
                _instance = null;
            }
        }

        #region 属性

        /// <summary>
        ///     单例模式
        /// </summary>
        public static T Instance
        {
            get
            {
                lock (_objLock)
                {
                    if (_instance != null) return _instance;
                    _instance = GetSetting();
                    return _instance;
                }
            }
            set
            {
                lock (_objLock)
                {
                    _instance = value;
                }
            }
        }

        #endregion

        #region 方法

        /// <summary>
        ///     读取本地配置
        /// </summary>
        /// <returns>基类为BaseSetting的对象</returns>
        private static T GetSetting()
        {
            var SettingPath = FullPath;
            if (File.Exists(SettingPath))
            {
                T result = default(T);
                DelayOnFile(() =>
                {
                    using (var fs = new FileStream(SettingPath, FileMode.Open, FileAccess.ReadWrite, FileShare.Read))
                    {
                        result = XmlSerializerHelper.DeSerialize<T>(fs);
                    }
                });
                return result;
            }

            return Activator.CreateInstance<T>();
        }

        /// <summary>
        ///     保存配置
        /// </summary>
        public void Save()
        {
            m_Watcher.EnableRaisingEvents = false;
            try
            {
                var path = Path.GetDirectoryName(FullPath);
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);
                DelayOnFile(() =>
                {
                    using (var fs = new FileStream(FullPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Read))
                    {
                        var ns = new XmlSerializerNamespaces();
                        ns.Add("", "");
                        XmlSerializerHelper.Serialize(fs, _instance, ns);
                    }
                });
            }
            catch
            {
                throw;
            }
            finally
            {
                m_Watcher.EnableRaisingEvents = true;
            }

        }

        private static void DelayOnFile(Action action)
        {
            var startTime = DateTime.Now;
            while (true)
            {
                try
                {
                    action();
                    break;
                }
                catch (IOException)
                {
                    if ((DateTime.Now - startTime).TotalSeconds >= 30)
                        throw;
                }
            }
        }

        #endregion
    }
}
